<?php

namespace App\Services;

use Exception;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use WebSocket\Client;

class XFYUNService
{
    static public $url = "wss://spark-api.xf-yun.com/v2.1/chat";

    /**
     * @throws \WebSocket\BadOpcodeException
     * @throws Exception
     */
    static public function chat(array $message): string
    {
        $appId = config('app.xfyun_app_id');
        $apiKey = config("app.xfyun_app_key");
        $apiSecret = config('app.xfyun_app_secret');

        // 创建鉴权URL
        $authUrl = self::assembleAuthUrl("GET", self::$url, $apiKey, $apiSecret);
        $client = new Client($authUrl);

        // 发送数据到 WebSocket 服务器
        $client->send(self::getBody($appId, ["text" => $message]));

        // 从 WebSocket 服务器接收数据
        $assistantAnswer = "";
        while (true) {
            $response = $client->receive();
            $resp = json_decode($response, true);
            $code = Arr::get($resp, 'header.code', -1);
            if ($code != 0) {
                break;
            }
            $texts = Arr::get($resp, 'payload.choices.text');
            $assistantAnswer .= $texts[0]['content'];
            $status = Arr::get($resp, "header.status", -1);
            if ($status == 2) {
                break;
            }
        }
        return trim($assistantAnswer);
    }

    /**
     * @throws Exception
     */
    static public function assembleAuthUrl($method, $url, $apiKey, $apiSecret): string
    {
        if ($apiKey == "" && $apiSecret == "") {
            throw new Exception("鉴权错误");
        }

        $ul = parse_url($url);
        if ($ul === false) {
            throw new Exception("地址错误");
        }

        $timestamp = time();
        $rfc1123_format = gmdate("D, d M Y H:i:s \G\M\T", $timestamp);

        // 参与签名的字段 host, date, request-line
        $signString = array("host: " . $ul["host"], "date: " . $rfc1123_format, $method . " " . $ul["path"] . " HTTP/1.1");

        // 将签名字符串拼接成一个字符串
        $sign = implode("\n", $signString);

        // 对签名字符串进行HMAC-SHA256加密，得到签名结果
        $sha = hash_hmac('sha256', $sign, $apiSecret, true);
        $signature_sha_base64 = base64_encode($sha);

        // 将API密钥、算法、头部信息和签名结果拼接成一个授权URL
        $authUrl = "api_key=\"$apiKey\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"$signature_sha_base64\"";

        // 对授权URL进行Base64编码，并添加到原始地址后面作为查询参数
        $queries = [
            'host' => $ul['host'], 'date' => $rfc1123_format,
            'authorization' => base64_encode($authUrl),
        ];
        return $url . '?' . http_build_query($queries);
    }

    //构造参数体
    static function getBody($appid, $message): bool|string
    {
        $header = array(
            "app_id" => $appid,
            "uid" => "aef9f963-7"
        );

        $parameter = array(
            "chat" => array(
                "domain" => "generalv2",
                "temperature" => 0.5,
                "max_tokens" => 2048
            )
        );

        $payload = ["message" => $message];

        return json_encode(array(
            "header" => $header,
            "parameter" => $parameter,
            "payload" => $payload
        ));
    }
}
